package pers.chao.tool.date;

import pers.chao.tool.infrastructure.FuncInterface;
import pers.chao.tool.infrastructure.regex.RegexPattern;

import java.util.*;

/**
 * Description: 毫秒转换器
 *
 * @author W.Chao
 * @date 2020/12/5 11:24
 **/
public final class MillSeconds {
	public static final Long ONE_YEAR = 31536000000L;
	public static final Long ONE_MONTH_30 = 2592000000L;
	public static final Long ONE_MONTH_31 = 2678400000L;
	public static final Long ONE_MONTH_28 = 2419200000L;
	public static final Long ONE_MONTH_29 = 2505600000L;
	public static final Long ONE_WEEK = 604800000L;
	public static final Long ONE_DAY = 86400000L;
	public static final Long ONE_HOUR = 3600000L;
	public static final Long ONE_MINUTE = 60000L;
	public static final Long ONE_SECOND = 1000L;

	private static final List<Integer> DAYS_30_OF_MONTH = Arrays.asList(4, 6, 9, 11);
	private static final List<Integer> DAYS_31_OF_MONTH = Arrays.asList(1, 3, 5, 7, 8, 10, 12);

	private static final Map<TimeType, List<String>> UNIT_MAPPING = new HashMap<>();

	static {
		List<String> years = Arrays.asList(TimeConst.YEAR_ZH, TimeConst.YEAR, TimeConst.YEAR.toLowerCase(), TimeConst.YEAR.toUpperCase());
		List<String> weeks = Collections.singletonList(TimeConst.WEEK);
		List<String> days = Arrays.asList(TimeConst.DAY_ZH[0], TimeConst.DAY_ZH[1], TimeConst.DAY, TimeConst.DAY.toUpperCase(), TimeConst.DAY.toLowerCase());
		List<String> hours = Arrays.asList(TimeConst.HOUR_ZH, TimeConst.HOUR, TimeConst.HOUR.toLowerCase(), TimeConst.HOUR.toUpperCase());
		List<String> minutes = Arrays.asList(TimeConst.MINUTE_ZH, TimeConst.MINUTE, TimeConst.MINUTE.toLowerCase(), TimeConst.MINUTE.toUpperCase());
		List<String> seconds = Arrays.asList(TimeConst.SECOND_ZH, TimeConst.SECOND, TimeConst.SECOND.toUpperCase(), TimeConst.SECOND.toLowerCase());
		UNIT_MAPPING.put(TimeType.YEAR, years);
		UNIT_MAPPING.put(TimeType.WEEK, weeks);
		UNIT_MAPPING.put(TimeType.DAY, days);
		UNIT_MAPPING.put(TimeType.HOUR, hours);
		UNIT_MAPPING.put(TimeType.MINUTE, minutes);
		UNIT_MAPPING.put(TimeType.SECOND, seconds);
	}

	// 循环判断并获取单位对应的时间类型
	private static final FuncInterface.T2R<String, TimeType> UNIT_TESTING = (unit) -> {
		TimeType type = TimeType.NONE;
		if (RegexPattern.isZh(unit) || RegexPattern.isLetter(unit)) {
			for (Map.Entry<TimeType, List<String>> typeListEntry : UNIT_MAPPING.entrySet()) {
				List<String> valueList = typeListEntry.getValue();
				if (valueList.contains(unit)) {
					type = typeListEntry.getKey();
					break;
				}
			}
		}
		return type;
	};

	// 根据不同月份直接获取
	private static final FuncInterface.T2R<Integer, Long> SPECIAL_MONTH_TESTING = (month) -> {
		Long mill = 0L;
		if (DAYS_30_OF_MONTH.contains(month)) {
			mill = ONE_MONTH_30;
		} else if (DAYS_31_OF_MONTH.contains(month)) {
			mill = ONE_MONTH_31;
		}
		return mill;
	};

	/**
	 * 根据不同单位可以获取对应的毫秒数
	 *
	 * @param number
	 * @param unit
	 * @return
	 */
	public static Long get(Long number, String unit) {
		// 时间单位兼容判断
		TimeType timeType = UNIT_TESTING.apply(unit);
		switch (timeType) {
			case YEAR:
				return ONE_YEAR * number;
			case WEEK:
				return ONE_WEEK * number;
			case DAY:
				return ONE_DAY * number;
			case HOUR:
				return ONE_HOUR * number;
			case MINUTE:
				return ONE_MINUTE * number;
			case SECOND:
				return ONE_SECOND * number;
			default:
				return 0L;
		}
	}

	/**
	 * 根据月份直接获取
	 *
	 * @param month 从1开始
	 * @return
	 */
	public static Long getMonth(int month) {
		if (month <= 0 || month == 2 || month > 12) {
			return 0L;
		}
		return SPECIAL_MONTH_TESTING.apply(month);
	}

	/**
	 * 2月特殊判断
	 *
	 * @param year
	 * @return
	 */
	public static Long get2Month(int year) {
		return EasyDateUtil.isLeapYear(year) ? ONE_MONTH_29 : ONE_MONTH_28;
	}

	enum TimeType {
		YEAR,
		WEEK,
		DAY,
		HOUR,
		MINUTE,
		SECOND,
		NONE;
	}
}
